// ============================== 导入依赖 ============================== //

// ============================== 导出数字工具 ============================== //

export default {
  /**
   * 数字转千分位串 (支持带小数，保留几位请提交 toFixed )
   *
   * @param {Number} num    数字
   * @param {String} suffix 前缀
   * @param {String} suffix 前缀
   *
   * @return {String} 千分位串
   */
  numStr(num, prefix = '', suffix = '') {
    if (!/^-?\d+(\.\d+)?$/.test(+num)) return num
    return `${prefix}${getThousandStr(num)}${suffix}`
  },

  /**
   * 数字转纯中文串 (暂只支持正负一亿亿以内，不带小数)
   *
   * @param {Number} num    数字
   * @param {String} suffix 前缀
   * @param {String} suffix 前缀
   *
   * @return {String} 纯中文串
   */
  numCN(num, prefix = '', suffix = '') {
    if (!/^-?\d{1,16}(\.\d+)?$/.test(+num)) return num
    return `${prefix}${getChineseStr(num)}${suffix}`
  },

  /**
   * 数字转大写金额 (暂只支持万亿以下，超过两位的小数舍弃)
   *
   * @param {Number} num    数字
   * @param {String} suffix 前缀
   * @param {String} suffix 前缀
   *
   * @return {String} 大写金额
   */
  numMoney(num, prefix = '', suffix = '') {
    if (!/^-?\d{1,12}(\.\d+)?$/.test(+num)) return num
    return `${prefix}${getChineseMoneyStr(num)}${suffix}`
  },

  /**
   * 数字转百分比率 (支持带小数)
   *
   * @param {Number} num    数字
   * @param {Number} digit  位数
   * @param {String} suffix 前缀
   * @param {String} suffix 前缀
   *
   * @return {String} 百分比率
   */
  numPercent(num, digit = 0, prefix = '', suffix = '%') {
    if (!/^-?\d+(\.\d+)?$/.test(+num)) return num
    return `${prefix}${(num * 100).toFixed(digit)}${suffix}`
  },

  /**
   * 数字转中文年份 (1000 - 9999)
   *
   * @param {Number} num    数字
   * @param {String} suffix 前缀
   * @param {String} suffix 前缀
   *
   * @return {String} 中文年份
   */
  numYear(num, prefix = '', suffix = '年') {
    if (!/^[1-9]\d{3}$/.test(+num)) return ''
    return `${prefix}${getChineseYearStr(num)}${suffix}`
  },

  /**
   * 数字转中文月份 (1 - 12)
   *
   * @param {Number} num    数字
   * @param {String} suffix 前缀
   * @param {String} suffix 前缀
   *
   * @return {String} 中文月份
   */
  numMonth(num, prefix = '', suffix = '月') {
    if (!/^([1-9]|1[012])$/.test(+num)) return ''
    return `${prefix}${getChineseStr(num)}${suffix}`
  },

  /**
   * 数字转中文日份 (1 - 31)
   *
   * @param {Number} num    数字
   * @param {String} suffix 前缀
   * @param {String} suffix 前缀
   *
   * @return {String} 中文日份
   */
  numDay(num, prefix = '', suffix = '日') {
    if (!/^([1-9]|[12]\d|3[01])$/.test(+num)) return ''
    return `${prefix}${getChineseStr(num)}${suffix}`
  },

  /**
   * 数字转中文时钟 (0 - 23)
   *
   * @param {Number} num    数字
   * @param {String} suffix 前缀
   * @param {String} suffix 前缀
   *
   * @return {String} 中文时钟
   */
  numHour(num, prefix = '', suffix = '时') {
    if (!/^(\d|1\d|2[0-3])$/.test(+num)) return ''
    return `${prefix}${getChineseStr(num)}${suffix}`
  },

  /**
   * 数字转中文分钟 (0 - 59)
   *
   * @param {Number} num    数字
   * @param {String} suffix 前缀
   * @param {String} suffix 前缀
   *
   * @return {String} 中文分钟
   */
  numMinute(num, prefix = '', suffix = '分') {
    if (!/^(\d|[1-5]\d)$/.test(+num)) return ''
    return `${prefix}${getChineseStr(num)}${suffix}`
  },

  /**
   * 数字转中文秒钟 (0 - 59)
   *
   * @param {Number} num    数字
   * @param {String} suffix 前缀
   * @param {String} suffix 前缀
   *
   * @return {String} 中文秒钟
   */
  numSecond(num, prefix = '', suffix = '秒') {
    if (!/^(\d|[1-5]\d)$/.test(+num)) return ''
    return `${prefix}${getChineseStr(num)}${suffix}`
  },

  /**
   * 数字转中文星期 (1 - 7)
   *
   * @param {Number} num    数字
   * @param {String} suffix 前缀
   * @param {String} suffix 前缀
   *
   * @return {String} 中文星期
   */
  numWeek(num, prefix = '星期', suffix = '') {
    if (!/^[1-7]$/.test(+num)) return ''
    return `${prefix}${getChineseStr(num).replace('七', '日')}${suffix}`
  },

  /**
   * 数字转持续时间
   *
   * @param {Number} num   数字 (秒数)
   * @param {String} unit  单位 (只能在 '天,时,分,秒' 的基础上加字)
   * @param {String} empty 空白
   *
   * 天,时,分,秒 ——> 最大单位为天，最小单位为秒
   * 天,时 ——> 最小单位为时，多余的舍弃
   * 分,秒 ——> 最大单位为分，超过 60 分也是显示为 xxx 分
   * 天,秒 ——> 中间不使用时和分，直接显示不到一天的秒数
   *
   * @return {String} 持续时间
   */
  numDuring(num, unit = '天，小时，分，秒', empty = '-') {
    if (!this.isInt(+num)) return num
    return getDuringStr(num, unit, 4) || empty
  },

  /**
   * 数字转持续时间 (一项单位，多余舍弃，避免过长)
   *
   * @param {Number} num   数字 (秒数)
   * @param {String} unit  单位 (只能在 '天,时,分,秒' 的基础上加字)
   * @param {String} empty 空白
   *
   * @return {String} 持续时间
   */
  numDuringOne(num, unit = '天，小时，分，秒', empty = '-') {
    if (!this.isInt(+num)) return num
    return getDuringStr(num, unit, 1) || empty
  },

  /**
   * 数字转持续时间 (最多两项单位，多余舍弃，避免过长)
   *
   * @param {Number} num   数字 (秒数)
   * @param {String} unit  单位 (只能在 '天,时,分,秒' 的基础上加字)
   * @param {String} empty 空白
   *
   * @return {String} 持续时间
   */
  numDuringTwo(num, unit = '天，小时，分，秒', empty = '-') {
    if (!this.isInt(+num)) return num
    return getDuringStr(num, unit, 2) || empty
  },

  /**
   * 数字转持续时间 (一项浮点数值的单位，多余舍弃，避免过长)
   *
   * @param {Number} num   数字 (秒数)
   * @param {String} unit  单位 (只能在 '天,时,分,秒' 的基础上加字)
   * @param {String} empty 空白
   *
   * @return {String} 持续时间
   */
  numDuringFloat(num, unit = '天，小时，分，秒', empty = '-') {
    if (!this.isInt(+num)) return num
    return getDuringFloatStr(num, unit) || empty
  },
}

// ============================== 内部常量 ============================== //

const NUM = '零一二三四五六七八九'.split('')
const UNIT = '零十百千万十百千亿十百千万十百千'.split('')
const ZERO = '零零零零万零零零亿零零零万零零零'.split('')

const MONEY_NUM = '零壹贰叁肆伍陆柒捌玖'.split('')
const MONEY_UNIT = '零拾佰仟万拾佰仟亿拾佰仟'.split('')

const YEAR_NUM = '〇一二三四五六七八九'.split('')

// ============================== 内部方法 ============================== //

/**
 * 获取千分位串
 *
 * @param {Number} num 数字
 *
 * @return {String} 千分位串
 */
export const getThousandStr = (num) => {
  let [intStr, floatStr = ''] = `${+num}`.replace('-', '').split('.')
  let [intThousand, floatThousand] = ['', '']
  const sign = /-/.test(num) ? '-' : ''
  const point = floatStr ? '.' : ''

  while (intStr.length > 3) {
    intThousand = `,${intStr.slice(-3)}${intThousand}`
    intStr = intStr.slice(0, -3)
  }

  while (floatStr.length > 3) {
    floatThousand = `${floatThousand}${floatStr.slice(0, 3)},`
    floatStr = floatStr.slice(3)
  }

  return `${sign}${intStr}${intThousand}${point}${floatThousand}${floatStr}`
}

/**
 * 获取纯中文串 (暂只支持亿亿以下)
 *
 * @param {Number} num 数字
 *
 * @return {String} 纯中文串
 */
export const getChineseStr = (num) => {
  const str = `${+num}`

  // 快捷转换 0 - 99
  if (/^\d$/.test(str)) return NUM[str]
  if (/^[1-9]\d$/.test(str)) {
    const [a, b] = str.split('')
    return `${a === '1' ? '' : NUM[a]}十${b === '0' ? '' : NUM[b]}`
  }

  // 整数转换
  const sign = /-/.test(str) ? '负' : ''
  const [intStr, floatStr = ''] = str.replace('-', '').split('.')
  const intReverse = intStr.split('').reverse()
  const intList = intReverse.map((x, i) => (x === '0' ? ZERO[i] : `${NUM[x]}${UNIT[i]}`))
  let cnStr = intList.reverse().join('')
  cnStr = cnStr.replace(/零+/g, '零').replace(/(.)零(亿|万|$)/g, '$1$2')
  cnStr = cnStr.replace(/^一十/, '十')
  if (!floatStr) return `${sign}${cnStr}`

  // 小数转换
  const floatList = floatStr.split('').map((x) => NUM[x])
  return `${sign}${cnStr}点${floatList.join('')}`
}

/**
 * 获取大写金额 (暂只支持万亿以下)
 *
 * @param {Number} num 数字
 *
 * @return {String} 大写金额
 */
export const getChineseMoneyStr = (num) => {
  const [intStr, floatStr] = (+num).toFixed(2).split('.')

  // 整数转换
  const strReverse = intStr.split('').reverse()
  const strList = strReverse.map((x, i) => (x === '0' ? `零${ZERO[i]}` : `${MONEY_NUM[x]}${MONEY_UNIT[i]}`))
  let money = strList.reverse().join('')
  money = money.replace(/零+/g, '零').replace(/(零)([亿万])/g, '$2$1')
  money = money.replace(/亿零?万?零?零/, '亿零').replace(/万零零/, '万零')
  money = money.replace(/(.+)零$/, '$1') + '元'
  if (floatStr === '00') return `${money}整`

  // 小数转换
  const [a, b] = floatStr.split('')
  return `${money}${a === '0' ? '零' : `${MONEY_NUM[a]}角`}${b === '0' ? '' : `${MONEY_NUM[b]}分`}`
}

/**
 * 获取中文年份 (1000 - 9999)
 *
 * @param {Number} num 数字
 *
 * @return {String} 中文年份
 */
export const getChineseYearStr = (num) => {
  const yearStrs = `${+num}`.split('').map((x) => YEAR_NUM[x])
  return yearStrs.join('')
}

/**
 * 获取持续时间
 *
 * @param {Number} num   数字
 * @param {String} unit  单位
 * @param {Number} limit 项数
 *
 * @return {String} 持续时间
 */
export const getDuringStr = (num, unit, limit) => {
  const unitList = unit.replace(/，/g, ',').split(',')

  let seconds = +num
  let during = ''
  let count = 0

  for (const item of unitList) {
    if (count === limit) break

    if (item.includes('天')) {
      const days = seconds / 86400 | 0
      if (days) {
        seconds = seconds % 86400
        during += `${days}${item}`
        count++
      }
    } else if (item.includes('时')) {
      const hours = seconds / 3600 | 0
      if (hours) {
        seconds = seconds % 3600
        during += `${hours}${item}`
        count++
      }
    } else if (item.includes('分')) {
      const minutes = seconds / 60 | 0
      if (minutes) {
        seconds = seconds % 60
        during += `${minutes}${item}`
        count++
      }
    } else if (item.includes('秒')) {
      if (seconds) during += `${seconds}${item}`
    }
  }

  return during
}

/**
 * 获取浮点数值单位的持续时间
 *
 * @param {Number} num   数字
 * @param {String} unit  单位
 *
 * @return {String} 持续时间
 */
export const getDuringFloatStr = (num, unit) => {
  const unitList = unit.replace(/，/g, ',').split(',')
  const trans = (count, item) => `${count.toFixed(1).replace(/\.0$/, '')}${item}`
  const seconds = +num

  for (const item of unitList) {
    if (item.includes('天')) {
      const days = seconds / 86400
      if (days >= 1) return trans(days, item)
    }

    if (item.includes('时')) {
      const hours = seconds / 3600
      if (hours >= 1) return trans(hours, item)
    }

    if (item.includes('分')) {
      const minutes = seconds / 60
      if (minutes >= 1) return trans(minutes, item)
    }

    if (item.includes('秒')) {
      if (seconds >= 1) return trans(seconds, item)
    }
  }
}
